# 参考：https://stackoverflow.com/questions/16056793/python-win32com-client-dispatch-looping-through-word-documents-and-export-to-pdf

import threading
import os
import os.path
from win32com import client as wc
import pythoncom
import PySimpleGUI as sg

def get_names(src_folder_path, src_ext='.doc', new_ext ='.docx', target_folder_path=None):
    basenames = [name for name in os.listdir(src_folder_path)
             if os.path.isfile(os.path.join(src_folder_path, name)) and name.endswith(src_ext)]
    filenames = [os.path.splitext(basename)[0] for basename in basenames]
    # 老文件名路径，含扩展名
    oldnames_fullpath = [os.path.join(src_folder_path, name) for name in basenames]
    # 老文件名路径，不含扩展名
    oldnames_fullpath_withoutext = [os.path.splitext(oldname_path)[0] for oldname_path in oldnames_fullpath]

    # 新文件名路径，含扩展名
    if target_folder_path is None or target_folder_path=='':
        newnames_fullpath = [name_without_ext + new_ext for name_without_ext in oldnames_fullpath_withoutext]
    else:
        # 如果目标路径不是以反斜杠结尾，则加上反斜杠
        if not target_folder_path.endswith('\\'):
            target_folder_path = target_folder_path + '\\'
        newnames_fullpath = [os.path.join(target_folder_path, name) + new_ext for name in filenames]

    # 总文件数
    cnt = len(oldnames_fullpath)
    # 新旧文件对
    old_new_pair = zip(oldnames_fullpath, newnames_fullpath)
    return old_new_pair, cnt

def TransBatch(src_folder_path, window, out_format_number = 16, src_ext='.doc', new_ext='.docx', target_folder_path=None):
    # 源格式和目标格式相同时，不执行转换
    if (src_ext==new_ext):
        window.write_event_value('-NOTHING-', '')
        return

    old_new_pairs, total_cnt = get_names(src_folder_path, src_ext, new_ext, target_folder_path)

    pythoncom.CoInitialize() #多线程中需要调用CoInitialize()方法，非多线程不需要
    word = wc.DispatchEx('Word.Application')
    for index, pair in enumerate(old_new_pairs):
        old_file, new_file = pair[0], pair[1]
        # print(old_file, new_file)
        # 打开 旧word 文件
        doc = word.Documents.Open(old_file)
        # 保存为 新word 文件,其中参数 16 表示的是docx文件, 17表示pdf文件,0表示doc文件；调用SaveAS时会自动添加扩展名
        doc.SaveAs(new_file, out_format_number)
        # 关闭word文档
        doc.Close()
        print(f"{new_file} 生成完毕！")
        # 发送事件，用于更新UI
        window.write_event_value('-Part_DONE-', f"第{index+1}/{total_cnt}个文件：{new_file} 生成完毕！")
    word.Quit()
    pythoncom.CoUninitialize()
    window.write_event_value('-DONE-', '')

if __name__ == "__main__":
    # 原始文件的后缀（扩展名）
    src_dict ={'Radio_DOC':'.doc', 'Radio_DOCX': '.docx'}
    # 输出格式，必须使用代码表示, 参考：https://docs.microsoft.com/en-us/office/vba/api/word.wdsaveformat
    format_dict = {}
    format_dict.update({'docx': {'ext': '.docx', 'formatType': 16}})
    format_dict.update({'pdf': {'ext': '.pdf', 'formatType': 17}})
    format_dict.update({'doc': {'ext': '.doc', 'formatType': 0}})

    src_ext = '.doc' #默认原始文件扩展名为.doc
    new_ext = '.docx'
    out_format_number = 16 #默认目标格式给docx，代码为16
    target_folder_path = None

    sg.theme('DefaultNoMoreNagging')

    layout = [[sg.Text('请输入文件夹名称（包含doc或docx文档）', font=('Helvetica', 11))],
              [sg.Input(key='-IN-'), sg.Button('开始转换', key='Convert')],
              [sg.Text('原始格式：', font=('Helvetica', 9), justification='left'),
               sg.Radio('DOC', 'SRC', key='Radio_DOC', default=True, enable_events=True, size=(10, 1)),
               sg.Radio('DOCX', 'SRC', key='Radio_DOCX', enable_events=True, size=(10, 1))],
              [sg.Text('目标格式：', font=('Helvetica', 9), justification='left'),
               sg.Radio('TO DOCX', 'FORMAT', key='docx', default=True, enable_events=True, size=(10, 1)),
               sg.Radio('TO PDF', 'FORMAT', key='pdf', enable_events=True, size=(10, 1)),
               sg.Radio('TO DOC', 'FORMAT', key='doc', enable_events=True, size=(10, 1))
               ],
              [sg.Text('输出文件夹：', font=('Helvetica', 9), tooltip='默认输出文件夹与输入相同', justification='left'),
               sg.Input(key='-target-')],
              [sg.Text(key='-OUT-')]
             ]

    window = sg.Window('word文件批量转换器', layout)
    while True:
        event, values = window.read()
        if event == sg.WINDOW_CLOSED:
            break
        elif event in ['Radio_DOC','Radio_DOCX']:
            src_ext = src_dict[event]
        elif event in ['docx', 'pdf', 'doc']: #点击了Radio触发该事件
            out_format_number = format_dict[event]['formatType']
            new_ext = format_dict[event]['ext']
        elif event == 'Convert':
            folder_path = values['-IN-']
            if len(folder_path) == 0:
                sg.popup('温馨提示', '请输入文件夹名称', values['-IN-'])
            else:
                target_folder_path = values['-target-'] if len(values['-target-']) > 0 else None
                threading.Thread(target=TransBatch, args=(folder_path, window, out_format_number, src_ext, new_ext, target_folder_path, ), daemon=True).start()
                # 转换结束之前，按钮不可用
                window['Convert'].update(disabled=True)
                window['-OUT-'].update('开始转换......')
        elif event == '-DONE-':
            window['-OUT-'].update('转换完毕！')
            # 转换结束，按钮可用
            window['Convert'].update(disabled=False)
            window.refresh()
        elif event=='-NOTHING-':
            # print(event)
            window['-OUT-'].update('目标格式和源格式相同，什么都不干！')
            # 转换结束，按钮可用
            window['Convert'].update(disabled=False)
            window.refresh()
        elif event=='-Part_DONE-':
            window['-OUT-'].update(values[event])
            window.refresh()
        # print(values)
    window.close()

